﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TA.DotNetUtils;
using System.Web.UI.HtmlControls;
using System.Web.UI;

namespace TA.Turbo.Design
{
	/// <summary>
	/// When implemented, provides a way to get a list of control IDs on a page.
	/// </summary>
	public abstract class BaseControlIdLister
	{
		#region PUBLIC
		#region INIT
		#endregion
		#region EVENTS
		#endregion
		#region PROPS
		#endregion
		#region METHODS
		/// <summary>
		/// Gets the list of control IDs, basing on the specified starting point control.
		/// </summary>
		/// <param name="startingPoint"></param>
		/// <returns></returns>
		public virtual string[] GetControlIdList(Control startingPoint)
		{
			List<string> res = new List<string>();

			this.AddIds(res, startingPoint);


			return res.ToArray();
		}

		#endregion
		#endregion
		#region INTERNAL
		#region CONST/STATIC
		#endregion
		#region VARS
		#endregion
		#region PROPS
		/// <summary>
		/// Gets the scope where to look for the controls.
		/// </summary>
		protected virtual ControlIdListingScope Scope
		{
			get
			{
				return ControlIdListingScope.Local;
			}
		}
		#endregion
		#region METHODS
		#region INIT
		#endregion
		#region DATA
		/// <summary>
		/// Adds the IDs of the controls to the specified string collection.
		/// </summary>
		/// <param name="res"></param>
		/// <param name="startingPoint"></param>
		protected virtual void AddIds(List<string> res, Control startingPoint)
		{
			if ((this.Scope & ControlIdListingScope.Local) == ControlIdListingScope.Local)
			{
				res.AddRange(this.GetControlIdList_Fill(startingPoint, startingPoint.NamingContainer, true, c => c.ID));
			}
			if ((this.Scope & ControlIdListingScope.Global) == ControlIdListingScope.Global)
			{
				res.AddRange(this.GetControlIdList_Fill(startingPoint, startingPoint.Page, false, c => c.UniqueID));
			}
		}
		List<string> GetControlIdList_Fill(Control referringControl, Control rootControl, bool localOnly, Func<Control, string> idSelector)
		{
			List<string> res = new List<string>();

			rootControl.ForEachRecursive(delegate(Control c)
			{
				if (c == referringControl || string.IsNullOrEmpty(c.ID))
					return;
				if (localOnly && c.NamingContainer != rootControl)
					return;

				if (this.ControlMatches(c))
					res.Add(idSelector(c));
			});

			res.Sort(StringComparer.OrdinalIgnoreCase);
			return res;
		}
		/// <summary>
		/// When implemented, determines and returns a flag which indicates whether the specified control should be included in the result.
		/// </summary>
		/// <param name="c"></param>
		/// <returns></returns>
		protected abstract bool ControlMatches(Control c);
		#endregion
		#region HANDLERS
		#endregion
		#endregion
		#endregion		
	}
	/// <summary>
	/// Specifies the scope (naming container) where to look for the controls during a listing operation.
	/// </summary>
	public enum ControlIdListingScope
	{
		/// <summary>
		/// No scope specified (ie., no controls returned).
		/// </summary>
		None = 0,
		/// <summary>
		/// Only return controls which share the naming container with the starting point control.
		/// </summary>
		Local = 1 << 0,
		/// <summary>
		/// Return all controls on the whole page.
		/// </summary>
		Global = 1 << 1,
		/// <summary>
		/// Returns controls which share the nameing container with the starting point, and then all controls on the page.
		/// </summary>
		Both = Local | Global,
	}
}
